package org.restorator.di;

import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.hamcrest.core.Is;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.restorator.exception.CyclicReferencesException;

import java.lang.reflect.InvocationTargetException;

import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.core.Is.*;

/**
 * @author Snisar Bogdan.
 */
public class Builder {

    ServiceBuilder b;

    @Before
    public void Before() {
        b = new ServiceBuilder();
    }


    @Test
    public void appendNewServ() throws ClassNotFoundException {
        b.appendService("foo", "org.restorator.di.Foo", true);
        b.appendService("bar", "org.restorator.di.Bar", true);
        System.out.println(b.container);
    }

    @Test
    public void appendMethodWithEmptyArgs() throws ClassNotFoundException, NoSuchMethodException {
        b.appendService("foo", "org.restorator.di.Foo", true);
        b.appendService("bar", "org.restorator.di.Bar", true);
        String[] strings = {"fooRun"};
        Object[][] ar = new Object[1][0];
        b.appendMethods("foo", strings, ar);
        Assert.assertFalse("Empty container", b.container.isEmpty());
        System.out.println(b.container);
    }

    @Test
    public void appendMethodWithArgs() throws ClassNotFoundException, NoSuchMethodException {
        b.appendService("foo", "org.restorator.di.Foo", true);
        b.appendService("bar", "org.restorator.di.Bar", true);
        String[] strings = {"runRar"};
        Object arg = null;
        arg = 5;
        Object[][] ar = {
                {arg}
        };
        b.appendMethods("bar", strings, ar);

        assertThat(b.container.get("bar").methods, not(arrayWithSize(0)));
        System.out.println(b.container);
    }

    @Test
    public void addDependedInConstructorRef() throws ClassNotFoundException, NoSuchMethodException {
        b.appendService("foo", "org.restorator.di.Foo", true);
        b.appendService("bar", "org.restorator.di.Bar", true);

        Object arg = b.container.get("bar");
        Object[] ar = {
                arg
        };

        b.appendConstructor("foo", null, ar);

        Ref foo = b.container.get("foo");
        assertThat(foo.constructor, notNullValue());
        assertThat(foo.parentRef, nullValue());
        assertThat(foo.childRef, not(emptyIterable()));
        System.out.println(b.container);
    }

    @Test(expected = CyclicReferencesException.class)
    public void addCyclicRefInChain() throws ClassNotFoundException, NoSuchMethodException {
        b.appendService("foo", "org.restorator.di.Foo", true);
        b.appendService("bar", "org.restorator.di.Bar", true);
        b.appendService("roo", "org.restorator.di.Roo", true);

        Object arg = b.getRefFromKey("bar");
        Object[] ar = {
                arg
        };
        b.appendConstructor("foo", null, ar);

        Object arg1 = b.getRefFromKey("roo");
        Object[] ar1 = {
                arg1
        };
        b.appendConstructor("bar", null, ar1);

        Object arg2 = b.getRefFromKey("foo");
        Object[] ar2 = {
                arg2
        };
        b.appendConstructor("roo", null, ar2);
    }

    @Test
    public void createObject() throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
        b.appendService("foo", "org.restorator.di.Foo", true);
        b.appendService("bar", "org.restorator.di.Bar", false);
        ServiceFactory f = new ServiceFactory(b);


        Object o = f.get("foo");
        Object o1 = f.get("foo");
        Object o2 = f.get("foo");
        System.out.println("new: " + o);
        System.out.println("new: " + o1);
        System.out.println("new: " + o2);
        System.out.println("new " + f.get("bar"));
        System.out.println("new " + f.get("bar"));
        Assert.assertNotNull(o);
    }
}
